Scanner 是 Java 內建的輸入工具,用來讀取使用者輸入。
String host = readHost(scanner);
int[] range = readPortRange(scanner);
從已建立的 Scanner scanner 呼叫你之前寫好的兩個輸入處理函式,回傳 host 字串 和 回傳一個 int 陣列 [startPort, endPort]。接著你通常會把它們傳給掃描函式去開始掃描。
package day1;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Day11Demo {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
String host =readHost(scanner);
int[] range = readPortRange(scanner);
System.out.println("\n===== 設定完成 =====");
System.out.println("Host: " + host);
try{ InetAddress resolved = InetAddress.getByName(host);
System.out.println("Resolved IP: " + resolved.getHostAddress());
}catch (UnknownHostException e) {
System.out.println("無法解析 host: " + host);
}System.out.println("Port 範圍: " + range[0] + " ~ " + range[1]);
startScan(host, range[0], range[1]);
}
}
private static String readHost(Scanner scanner) {
while (true) {
System.out.println("請輸入host:" );
String host = scanner.nextLine().trim();
if (!host.isEmpty()) return host;
System.out.println("Host 不能為空,請重新輸入。");
}
}
private static int[] readPortRange(Scanner scanner) {
while (true) {
System.out.println("請輸入 Port 或範圍 (例如 80 或 20-1024):");
String line = scanner.nextLine().trim();
try {
return parsePortRange(line);
}catch (IllegalArgumentException ex) {
System.out.println("輸入錯誤:"+ex.getMessage());
}
}
}
private static int[] parsePortRange(String input){
if (input.isEmpty())throw new IllegalArgumentException("不能為空");
if (!input.contains("-")){
int p =parsePortNumber(input);
return new int[]{p,p};
}
String[] parts=input.split("-",2);
int start=parsePortNumber(parts[0].trim());
int end=parsePortNumber(parts[1].trim());
if (start > end) throw new IllegalArgumentException("起始 port 不能大於結束 port。");
return new int[] { start, end };
}
private static int parsePortNumber(String s){
try{
int p = Integer.parseInt(s);
if(p<1 || p>65535) throw new IllegalArgumentException("Port 必須在 1-65535。");
return p;
}catch (NumberFormatException e) {
throw new IllegalArgumentException("Port 必須為整數。");
}
}
private static void startScan(String host, int startPort, int endPort) {
System.out.println("\n開始掃描...");
for (int port = startPort; port <= endPort; port++) {
try (Socket socket = new Socket()) {
socket.connect(new java.net.InetSocketAddress(host, port), 1000);
System.out.printf("Port %d -> OPEN%n", port);
} catch (IOException e) {
System.out.printf("Port %d -> CLOSED/TIMEOUT%n", port);
}
}
System.out.println("掃描結束。");
}
}
1.private static String readHost(Scanner scanner)
用途:讀使用者輸入的 host(例如 localhost ),保證不會是空字串。
2. private static int[] readPortRange(Scanner scanner)
用途:讀使用者輸入的 port 或 port 範圍(例如 80 或 20-1024),保證格式正確且範圍合法。
3. private static int[] parsePortRange(String input)
用途:把使用者輸入的字串解析成 [startPort, endPort] 陣列。
簡單理解:把 "80" → [80, 80],把 "20-1024" → [20, 1024],並檢查數字合法性。
4. private static int parsePortNumber(String s)
用途:把字串轉成整數 port,並檢查是否在 1~65535 範圍內。
5. private static void startScan(String host, int startPort, int endPort)
用途:用 Socket 逐個掃描指定範圍內的 port,並印出 OPEN 或 CLOSED/TIMEOUT。
簡單理解:真正開始掃描 port,把結果印出來。
今天這段程式碼用箭頭圖解釋:
使用者啟動程式
│
▼
讀取 Host (readHost)
│
├─> 如果空字串 → 提示重新輸入 → 回到讀取 Host
│
▼
讀取 Port 範圍 (readPortRange)
│
├─> 如果格式錯誤或超出範圍 → 提示重新輸入 → 回到讀取 Port
│
▼
解析 Host 名稱 (InetAddress.getByName)
│
├─> 成功 → 印出 Resolved IP
│
└─> 失敗 → 印出「無法解析 host」 → 可以結束程式或重新輸入
│
▼
開始掃描 Port (startScan)
│
├─> 迴圈從 startPort 到 endPort
│ │
│ ▼
│ 嘗試連線 Socket
│ │
│ ├─> 成功 → 印出 Port X -> OPEN
│ │
│ └─> 失敗/超時 → 印出 Port X -> CLOSED/TIMEOUT
│
▼
掃描結束 → 印出「掃描結束。」
│
▼
程式結束
過程中遇到的問題:
不懂InetAddress.getByName(host) 做了什麼?
它會嘗試把使用者輸入的 host 名稱 轉換成 IP 位址
例如: "localhost" → "127.0.0.1"
"google.com" → "142.250.190.78"(每次可能不同)
今天學到了用 Scanner 讓輸入者輸入 host,接下來輸入port範圍,程式也會看有沒有錯誤,也用了迴圈,直到輸入成功為止,然後查詢host的IP位址。
最後開始掃描輸入者輸入port的範圍,每個port都會掃描是否開啟(CLOSED/TIMEOUT)。也有用到昨天學習的Socket, 用 try-with-resources 每次連線掃描後自動關閉。